package com.lframework.starter.web.inner.impl.system;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageInfo;
import com.lframework.starter.common.constants.StringPool;
import com.lframework.starter.common.exceptions.impl.DefaultClientException;
import com.lframework.starter.common.utils.StringUtil;
import com.lframework.starter.web.core.annotations.oplog.OpLog;
import com.lframework.starter.web.core.components.resp.PageResult;
import com.lframework.starter.web.core.impl.BaseMpServiceImpl;
import com.lframework.starter.web.core.utils.IdUtil;
import com.lframework.starter.web.core.utils.OpLogUtil;
import com.lframework.starter.web.core.utils.PageHelperUtil;
import com.lframework.starter.web.core.utils.PageResultUtil;
import com.lframework.starter.web.inner.components.oplog.SystemOpLogType;
import com.lframework.starter.web.inner.entity.SysDept;
import com.lframework.starter.web.inner.entity.SysDeptLogo;
import com.lframework.starter.web.inner.entity.SysUserDept;
import com.lframework.starter.web.inner.mappers.system.SysDeptLogoMapper;
import com.lframework.starter.web.inner.service.RecursionMappingService;
import com.lframework.starter.web.inner.service.system.SysDeptLogoService;
import com.lframework.starter.web.inner.service.system.SysDeptService;
import com.lframework.starter.web.inner.service.system.SysUserDeptService;
import com.lframework.starter.web.inner.vo.system.dept.logo.CreateSysDeptLogoVo;
import com.lframework.starter.web.inner.vo.system.dept.logo.QuerySysDeptLogoVo;
import com.lframework.starter.web.inner.vo.system.dept.logo.UpdateSysDeptLogoVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Service
public class SysDeptLogoServiceImpl extends BaseMpServiceImpl<SysDeptLogoMapper, SysDeptLogo>
        implements SysDeptLogoService {

    @Autowired
    private SysUserDeptService sysUserDeptService;

    @Autowired
    private SysDeptService sysDeptService;

    @Autowired
    private RecursionMappingService recursionMappingService;

    @Override
    public PageResult<SysDeptLogo> query(Integer pageIndex, Integer pageSize, QuerySysDeptLogoVo vo) {
        PageHelperUtil.startPage(pageIndex, pageSize);
        List<SysDeptLogo> datas = this.doQuery(vo);
        return PageResultUtil.convert(new PageInfo<>(datas));
    }

    @Cacheable(value = SysDeptLogo.CACHE_NAME, key = "@cacheVariables.tenantId() + #id", unless = "#result == null")
    @Override
    public SysDeptLogo findById(String id) {
        return this.doFindById(id);
    }

    @Override
    public List<SysDeptLogo> findByDeptId(String deptId) {
        return this.doFindByDeptId(deptId);
    }

    @OpLog(type = SystemOpLogType.class, name = "新增部门Logo，ID：{}, 名称：{}", params = {"#id", "#name"})
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String create(CreateSysDeptLogoVo vo) {
        SysDeptLogo data = this.doCreate(vo);

        OpLogUtil.setVariable("id", data.getId());
        OpLogUtil.setVariable("name", vo.getName());
        OpLogUtil.setExtra(vo);

        return data.getId();
    }

    @OpLog(type = SystemOpLogType.class, name = "修改部门Logo，ID：{}, 名称：{}", params = {"#id", "#name"})
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void update(UpdateSysDeptLogoVo vo) {
        this.doUpdate(vo);

        OpLogUtil.setVariable("id", vo.getId());
        OpLogUtil.setVariable("name", vo.getName());
        OpLogUtil.setExtra(vo);
    }

    @OpLog(type = SystemOpLogType.class, name = "删除部门Logo，ID：{}", params = "#id")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteById(String id) {
        SysDeptLogo data = this.findById(id);
        if (data == null) {
            throw new DefaultClientException("部门Logo不存在！");
        }

        this.doDeleteById(id);

        OpLogUtil.setVariable("id", id);
    }

    @OpLog(type = SystemOpLogType.class, name = "根据部门ID删除部门Logo，部门ID：{}", params = "#deptId")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteByDeptId(String deptId) {
        this.doDeleteByDeptId(deptId);

        OpLogUtil.setVariable("deptId", deptId);
    }

    protected List<SysDeptLogo> doQuery(QuerySysDeptLogoVo vo) {
        return getBaseMapper().query(vo);
    }

    protected SysDeptLogo doFindById(String id) {
        return getBaseMapper().findById(id);
    }

    protected List<SysDeptLogo> doFindByDeptId(String deptId) {
        return getBaseMapper().findByDeptId(deptId);
    }

    protected SysDeptLogo doCreate(CreateSysDeptLogoVo vo) {
        SysDeptLogo data = new SysDeptLogo();
        data.setId(IdUtil.getId());
        data.setName(vo.getName());
        data.setUrl(vo.getUrl());
        data.setObjectName(StringPool.EMPTY_STR); // 可以根据实际需求设置
        data.setDeptId(vo.getDeptId());

        this.save(data);

        return data;
    }

    protected void doUpdate(UpdateSysDeptLogoVo vo) {
        SysDeptLogo record = this.findById(vo.getId());
        if (record == null) {
            throw new DefaultClientException("部门Logo不存在！");
        }

        // 检查同部门下名称是否重复
        if (!StringUtil.isBlank(vo.getDeptId())) {
            Wrapper<SysDeptLogo> checkWrapper = Wrappers.lambdaQuery(SysDeptLogo.class)
                    .eq(SysDeptLogo::getDeptId, vo.getDeptId())
                    .eq(SysDeptLogo::getName, vo.getName())
                    .ne(SysDeptLogo::getId, vo.getId());
            if (this.count(checkWrapper) > 0) {
                throw new DefaultClientException("该部门下已存在相同名称的Logo！");
            }
        }

        record.setName(vo.getName());
        record.setUrl(vo.getUrl());
        record.setDeptId(vo.getDeptId());

        this.updateById(record);
    }

    protected void doDeleteById(String id) {
        this.removeById(id);
    }

    protected void doDeleteByDeptId(String deptId) {
        Wrapper<SysDeptLogo> deleteWrapper = Wrappers.lambdaQuery(SysDeptLogo.class)
                .eq(SysDeptLogo::getDeptId, deptId);
        this.remove(deleteWrapper);
    }

    @Override
    public Set<String> findUserDeptLogos(String userId) {
        Set<String> logoUrls = new HashSet<>();

        // 获取用户所属的所有部门
        List<SysUserDept> userDepts = sysUserDeptService.getByUserId(userId);
        if (userDepts == null || userDepts.isEmpty()) {
            return logoUrls;
        }

        // 遍历用户所属的每个部门，查找Logo
        for (SysUserDept userDept : userDepts) {
            Set<String> deptLogos = findDeptLogosRecursively(userDept.getDeptId());
            logoUrls.addAll(deptLogos);
        }

        return logoUrls;
    }

    @CacheEvict(value = {SysDeptLogo.CACHE_NAME}, key = "@cacheVariables.tenantId() + #key")
    @Override
    public void cleanCacheByKey(Serializable key) {

    }

    /**
     * 递归查询部门及其上级部门的Logo
     *
     * @param deptId 部门ID
     * @return Logo地址列表
     */
    private Set<String> findDeptLogosRecursively(String deptId) {
        Set<String> logoUrls = new HashSet<>();

        if (StringUtil.isBlank(deptId)) {
            return logoUrls;
        }

        // 先查询当前部门的Logo
        List<SysDeptLogo> currentDeptLogos = this.findByDeptId(deptId);
        if (currentDeptLogos != null && !currentDeptLogos.isEmpty()) {
            for (SysDeptLogo logo : currentDeptLogos) {
                if (StringUtil.isNotBlank(logo.getUrl())) {
                    logoUrls.add(logo.getUrl());
                }
            }
            // 如果当前部门有Logo，直接返回，不再向上查询
            return logoUrls;
        }

        // 如果当前部门没有Logo，查询父级部门
        SysDept currentDept = sysDeptService.findById(deptId);
        if (currentDept != null && StringUtil.isNotBlank(currentDept.getParentId())) {
            // 递归查询父级部门的Logo
            logoUrls.addAll(findDeptLogosRecursively(currentDept.getParentId()));
        }

        return logoUrls;
    }

}